home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of MacTutor - S…e Code for Volumes 1 to 5
/
The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin
/
Source Code
/
#27 (Dec 87)
/
c daisy printer driver
/
PDEF4.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-09-29
|
15KB
|
510 lines
/*
* PDEF4.c.
*
* Generic daisy/dot matrix text printer driver for the Macintosh.
* Earle R. Horton August 31, 1987
* All rights reserved.
*
* This module contains the code for validating, creating,
* and modifying print records.
*/
/*
* This module is to be placed into a code resource project using LightspeedC,
* version 2.01 or greater. The project is to be made into PDEF resource
* number 4. All of the code up to and including the first illegal instruction
* is to be stripped off, so that the PDEF will have the standard format for
* resources of this type. Switch statements cannot be used, since LightspeedC
* compiles them into separate code which is added to the beginning of the
* code resource, before our standard header. I do not know at this point
* which types of flow control constructs are safe, but I have determined by
* disassembly that the following will produce useable code:
* if, if/else blocks
* gotos
*
* Instructions, or "How I did it."
* Create from this module a code resource of type 'pdef' ID 4.
* Run the program utils.c to make it into PDEF ID 4 and to strip
* off the standard header.
*/
#include <DialogMgr.h>
#include <EventMgr.h>
#include "prglobals.h"
#define STYLEDIALOG (0xE000)
#define JOBDIALOG (0xE001)
#define XTRA 24 /* Six extra longs for our use. */
#define DLGSIZE ((long)(sizeof(TPrDlg) + XTRA))
#define TPSIZE ((long)(sizeof(TPrint)))
/* Items we handle in the job and style dialogs. */
#define CANCELITEM 2
#define CPI10BUTTON 4
#define CPI12BUTTON 5
#define CPI15BUTTON 6
#define STRAIGHTUPITEM 7
#define SIDEWAYSITEM 8
#define ALLBUTTON 5
#define RANGEBUTTON 6
#define FROMNUM 7
#define TONUM 9
#define COPIES 11
#define FANBUTTON 13
#define SHEETBUTTON 14
pascal void MyPrintDefault(); /* Fill a print record with defaults. */
pascal Boolean MyPrStlDialog(); /* Conduct printer style dialog. */
pascal Boolean MyPrJobDialog(); /* Conduct printer job dialog. */
pascal TPPrDlg MyPrStlInit(); /* Set up the style dialog. */
pascal TPPrDlg MyPrJobInit(); /* Set up the job dialog. */
pascal Boolean MyPrDlgMain(); /* Printing dialog supervisor function. */
pascal Boolean MyPrValidate(); /* Validate/update a print record. */
pascal void MyPrJobMerge(); /* Copy a job subrecord. */
pascal Boolean MyFilter(); /* Filter dialog events. */
pascal void HandleStyleItems(); /* Handle Style Items. */
pascal void HandleJobItems(); /* Handle Job Items. */
TPPrDlg TPPrDlgallocate();
void pushradiobutton();
int NumToString(),StringToNum();
Boolean Valid();
void mkDefault();
void free();
main()
{
asm{
dc.w ILLEGAL ;; So I can find it...
jmp MyPrintDefault
jmp MyPrStlDialog
jmp MyPrJobDialog
jmp MyPrStlInit
jmp MyPrJobInit
jmp MyPrDlgMain
jmp MyPrValidate
jmp MyPrJobMerge
}
}
/*
* This function fills a print record with defaults. The default values
* are stored in the Printer resource file, in PREC 0. This is easy. Then
* we check the fields of the print record for anything obviously illegal.
* If the default print record contains stuff that is bad, then we correct
* it and update the copy in the printer resource file. This should never
* happen, but some wise guy with a copy of ResEdit and more brains than
* sense may think he knows more than we do.
*/
pascal void MyPrintDefault(hPrint)
THPrint hPrint;
{
THPrint thedefault;
thedefault = (THPrint)(GetResource('PREC',0));
if(thedefault == nil){
mkDefault(hPrint);
}
else{
LoadResource(thedefault);
if(MyPrValidate(thedefault)) {
ChangedResource(thedefault);
WriteResource(thedefault);
}
**hPrint = **thedefault; /* What the hell. */
}
}
pascal Boolean MyPrStlDialog(hPrint) /* Conduct printer style dialog. */
THPrint hPrint;
{
return(MyPrDlgMain(hPrint,MyPrStlInit));
}
pascal Boolean MyPrJobDialog(hPrint) /* Conduct printer job dialog. */
THPrint hPrint;
{
return(MyPrDlgMain(hPrint,MyPrJobInit));
}
/*
* The style dialog initializer.
*/
pascal TPPrDlg MyPrStlInit(hPrint)
THPrint hPrint;
{
TPPrDlg tp;
tp = TPPrDlgallocate();
(GetNewDialog(STYLEDIALOG,tp,-1));
if((*hPrint)->prInfo.iDev == IDEV10)
pushradiobutton(tp,CPI10BUTTON,CPI10BUTTON,CPI15BUTTON);
else if((*hPrint)->prInfo.iDev == IDEV12)
pushradiobutton(tp,CPI12BUTTON,CPI10BUTTON,CPI15BUTTON);
else if((*hPrint)->prInfo.iDev == IDEV15)
pushradiobutton(tp,CPI15BUTTON,CPI10BUTTON,CPI15BUTTON);
pushradiobutton(tp,STRAIGHTUPITEM,STRAIGHTUPITEM,SIDEWAYSITEM);
tp->pFltrProc = (ProcPtr)MyFilter;
tp->pItemProc = (ProcPtr)HandleStyleItems;
tp->hPrintUsr = hPrint;
return(tp);
}
/*
* The job dialog initializer.
*/
pascal TPPrDlg MyPrJobInit(hPrint)
THPrint hPrint;
{
TPPrDlg tp;
int thenum;
Handle theitem;
Rect thebox;
Str36 title;
tp = TPPrDlgallocate();
(GetNewDialog(JOBDIALOG,tp,-1));
pushradiobutton(tp,ALLBUTTON,ALLBUTTON,RANGEBUTTON);
if( (*hPrint)->prStl.feed == feedCut)
pushradiobutton(tp,SHEETBUTTON,FANBUTTON,SHEETBUTTON);
else
pushradiobutton(tp,FANBUTTON,FANBUTTON,SHEETBUTTON);
GetDItem(tp,FROMNUM,&thenum,&theitem,&thebox);
thenum = (*hPrint)->prJob.iFstPage;
NumToString((long)thenum,title);
SetIText(theitem,title);
GetDItem(tp,TONUM,&thenum,&theitem,&thebox);
thenum = (*hPrint)->prJob.iLstPage;
NumToString((long)thenum,title);
SetIText(theitem,title);
GetDItem(tp,COPIES,&thenum,&theitem,&thebox);
thenum = (*hPrint)->prJob.iCopies;
NumToString((long)thenum,title);
SetIText(theitem,title);
tp->pFltrProc = (ProcPtr)MyFilter;
tp->pItemProc = (ProcPtr)HandleJobItems;
tp->hPrintUsr = hPrint;
return(tp);
}
pascal Boolean MyPrDlgMain(hPrint,pDlgInit)
/* Printing dialog supervisor function. */
/* Reference: Macintosh Technical Note */
/* 95. Good luck! */
THPrint hPrint;
ProcPtr pDlgInit;
{
TPPrDlg tp;
WindowPtr tempport;
int donetype,itemhit;
Handle doneitem;
Rect donebox;
ProcPtr itemproc;
asm{
subq.l #4,a7 ;; Room for function return.
move.l hPrint,-(a7) ;; Pass handle to print record.
move.l pDlgInit,a0 ;; Get address of dialog init routine.
jsr (a0) ;; It's a "Pascal" routine.
move.l (a7)+,tp ;; Pop return value.
}
itemproc = tp->pItemProc;
tp->fDone = FALSE;
tp->fDoIt = FALSE;
GetPort(&tempport);
SetPort(tp);
ShowWindow(tp);
GetDItem(tp,DONEITEM,&donetype,&doneitem,&donebox);
PenSize(3,3);
InsetRect(&donebox,-4,-4);
FrameRoundRect(&donebox,16,16);
while(!(tp->fDone)){
ModalDialog(tp->pFltrProc,&itemhit);
/*
* Reverse parameters on the call to pItemProc. The application is allowed
* to trap our pItemProc and insert its own, so we must use the Pascal
* calling conventions here. Programming novices can use the LightspeedC™
* CallPascal library if they want. You will have to be careful if you do
* this to make sure the library is linked AFTER the module containing these
* functions, or you won't get the PDEF resource header right.
*/
asm{
move.l tp,-(a7)
move.w itemhit,-(a7)
move.l itemproc,a0
jsr (a0)
}
}
SetPort(tempport);
CloseDialog(tp);
free(tp);
if(tp->fDoIt) (void)MyPrValidate(hPrint);
return(tp->fDoIt);
}
/*
* Validate/update a print record. Check all the fields for compatibility with
* our driver. This is a three stage process. First, we check all fields to
* see whether they are within the bounds which our driver can handle. If
* they are, we return FALSE (no change). If not, we obtain a copy of the
* current default values from the printer resource file. Then we inspect
* these to see if they are valid. If the default values in the printer
* resource file are valid, we use them, update the user's print record,
* and return TRUE (changed). Otherwise, we fall back on default values
* which we store in the code here. This three stage process provides some
* protection against the user who attempts to adjust the print record using
* a resource editor, and screws up.
*/
pascal Boolean MyPrValidate(hPrint) /* Validate/update a print record. */
THPrint hPrint;
{
THPrint thedefault;
if(Valid(hPrint)) return FALSE;
else{
thedefault = (THPrint)(GetResource('PREC',0));
LoadResource(thedefault);
if(thedefault == nil || !Valid(thedefault)) mkDefault(hPrint);
else{
**hPrint = **thedefault;
}
return TRUE;
}
}
pascal void MyPrJobMerge(hPrintSrc,hPrintDst)
/*
* Copy a job subrecord. Update the destination record's printer information,
* band information, and paper rectangle, based on information in the job
* subrecord.
*/
THPrint hPrintSrc,hPrintDst;
{
(*hPrintDst)->prInfo.iDev = (*hPrintSrc)->prInfo.iDev;
(*hPrintDst)->prJob = (*hPrintSrc)->prJob;
(*hPrintDst)->prXInfo = (*hPrintSrc)->prXInfo;
(*hPrintDst)->rPaper = (*hPrintSrc)->rPaper;
(*hPrintDst)->prInfo = (*hPrintSrc)->prInfo;
(*hPrintDst)->prInfoPT = (*hPrintSrc)->prInfoPT;
}
pascal Boolean MyFilter(thedialog,theEvent,itemhit)
DialogPtr thedialog;
EventRecord *theEvent;
int *itemhit;
{
if(theEvent->what == keyDown &&
(theEvent->message & charCodeMask) == 13){
*itemhit = 1;
return TRUE;
}
return FALSE;
}
/*
* The next routine handles the style dialog. Two possibilities exist.
* If the cancel button is hit, then we signal quit. The print record
* is not changed.
* If the done button is hit, we validate the user's print record.
* (MyPrDlgMain() calls MyPrValidate() to do this.)
* We use three radio buttons to determine the number of characters
* per inch (resolution), and two to determine paper orientation.
*/
pascal void HandleStyleItems(tp,itemhit)
TPPrDlg tp;
int itemhit;
{
int thenum;
Handle theitem;
Rect thebox;
if(itemhit >= CPI10BUTTON && itemhit <= CPI15BUTTON)
pushradiobutton(tp,itemhit,CPI10BUTTON,CPI15BUTTON);
else if(itemhit >= STRAIGHTUPITEM && itemhit <= SIDEWAYSITEM)
pushradiobutton(tp,itemhit,STRAIGHTUPITEM,SIDEWAYSITEM);
else if(itemhit == DONEITEM){
TPrint Print;
TPPrint pPrint;
pPrint = &Print;
mkDefault(&pPrint);
(*tp->hPrintUsr)->iPrVersion = Print.iPrVersion;
(*tp->hPrintUsr)->prInfo = Print.prInfo;
(*tp->hPrintUsr)->prXInfo = Print.prXInfo;
(*tp->hPrintUsr)->rPaper = Print.rPaper;
(*tp->hPrintUsr)->prStl = Print.prStl;
(*tp->hPrintUsr)->prInfoPT = Print.prInfoPT;
GetDItem(tp,CPI10BUTTON,&thenum,&theitem,&thebox);
if(GetCtlValue(theitem) == 1){
(*tp->hPrintUsr)->prInfo.iDev = IDEV10;
}
GetDItem(tp,CPI12BUTTON,&thenum,&theitem,&thebox);
if(GetCtlValue(theitem) == 1){
(*tp->hPrintUsr)->prInfo.iDev = IDEV12;
}
GetDItem(tp,CPI15BUTTON,&thenum,&theitem,&thebox);
if(GetCtlValue(theitem) == 1){
(*tp->hPrintUsr)->prInfo.iDev = IDEV15;
}
GetDItem(tp,SIDEWAYSITEM,&thenum,&theitem,&thebox);
if(GetCtlValue(theitem) == 1){
int temp;
flipRect(&(*tp->hPrintUsr)->prInfo.rPage);
flipRect(&(*tp->hPrintUsr)->rPaper);
flipRect(&(*tp->hPrintUsr)->prInfoPT.rPage);
temp = (*tp->hPrintUsr)->prStl.iPageV;
(*tp->hPrintUsr)->prStl.iPageV =
(*tp->hPrintUsr)->prStl.iPageH;
(*tp->hPrintUsr)->prStl.iPageH = temp;
}
tp->fDone = TRUE;
tp->fDoIt = TRUE;
}
else if (itemhit == CANCELITEM){
tp->fDone = TRUE;
tp->fDoIt = FALSE;
}
}
pascal void HandleJobItems(tp,itemhit)
TPPrDlg tp;
int itemhit;
{
int thenum;
long thelong;
Handle numitem;
Rect numbox;
Str36 title;
if(itemhit == DONEITEM){ /* NO SWITCHES! */
tp->fDone = TRUE; /* At least until I get a */
tp->fDoIt = TRUE; /* better compiler. */
GetDItem(tp,ALLBUTTON,&thenum,&numitem,&numbox);
if(GetCtlValue(numitem) == 1){
(*(tp->hPrintUsr))->prJob.iFstPage = iPrPgFst;
(*(tp->hPrintUsr))->prJob.iLstPage = iPrPgMax;
}
else{
GetDItem(tp,FROMNUM,&thenum,&numitem,&numbox);
GetIText(numitem,&title[0]);
StringToNum(&title[0],&thelong);
(*(tp->hPrintUsr))->prJob.iFstPage = thelong;
GetDItem(tp,TONUM,&thenum,&numitem,&numbox);
GetIText(numitem,&title[0]);
StringToNum(&title[0],&thelong);
(*(tp->hPrintUsr))->prJob.iLstPage = thelong;
}
GetDItem(tp,COPIES,&thenum,&numitem,&numbox);
GetIText(numitem,&title[0]);
StringToNum(&title[0],&thelong);
(*(tp->hPrintUsr))->prJob.iCopies = thelong;
GetDItem(tp,SHEETBUTTON,&thenum,&numitem,&numbox);
if(GetCtlValue(numitem) == 1){
(*(tp->hPrintUsr))->prStl.feed = feedCut;
}
else (*(tp->hPrintUsr))->prStl.feed = feedFanfold;
}
else if (itemhit == CANCELITEM){
tp->fDone = TRUE;
}
else if (itemhit == SHEETBUTTON){
pushradiobutton(tp,SHEETBUTTON,FANBUTTON,SHEETBUTTON);
(*(tp->hPrintUsr))->prStl.feed = feedCut;
}
else if (itemhit == FANBUTTON){
pushradiobutton(tp,FANBUTTON,FANBUTTON,SHEETBUTTON);
(*(tp->hPrintUsr))->prStl.feed = feedFanfold;
}
else if (itemhit == ALLBUTTON){
pushradiobutton(tp,ALLBUTTON,ALLBUTTON,RANGEBUTTON);
}
else if (itemhit == RANGEBUTTON){
pushradiobutton(tp,RANGEBUTTON,ALLBUTTON,RANGEBUTTON);
}
}
TPPrDlg TPPrDlgallocate()
{
TPPrDlg thepointer;
asm{
move.l #DLGSIZE,d0
NewPtr
move.l a0,thepointer
}
if(thepointer == nil){ /* We're in deep shit now! */
asm{
move.w #25,d0
SysError ;; SysError
}
}
return(thepointer);
}
void pushradiobutton(thedialog,itemhit,first,last) /* push a radio Button */
DialogPtr thedialog; /* set itemhit, unset */
int itemhit,first,last; /* all others in range */
{
int itemtype,i;
Handle itemhandle; /* Does check boxes, too. */
Rect itemrect;
if(first ==0) return;
for(i=first-1;last-i++;){
GetDItem(thedialog,i,&itemtype,&itemhandle,&itemrect);
if(i == itemhit) SetCtlValue(itemhandle,1);
else SetCtlValue(itemhandle,0);
}
}
NumToString(thenum,thestring)
long thenum;
char *thestring;
{
asm{
move.l thestring,a0
move.l thenum,d0
move.w #0,-(a7)
Pack7
}
}
StringToNum(thestring,thenum)
char *thestring;
long *thenum;
{
asm{
move.l thestring,a0
move.w #1,-(a7)
Pack7
move.l thenum,a0
move.l d0,(a0)
}
}
/*
* This function answers the question: Can we possibly use this print
* record?
*/
Boolean Valid(hPrint)
THPrint hPrint;
{
if (((*hPrint)->iPrVersion != VERSION)
|| ((*hPrint)->prInfo.iDev != IDEV12 &&
(*hPrint)->prInfo.iDev != IDEV10 &&
(*hPrint)->prInfo.iDev != IDEV15)
|| ((*hPrint)->prInfo.iVRes != VREZZ)
|| ((*hPrint)->prInfo.iHRes != HREZZ12)
|| ((*hPrint)->prInfo.rPage.top !=0 ||
(*hPrint)->prInfo.rPage.left !=0)
|| ((*hPrint)->rPaper.right -
(*hPrint)->rPaper.left > 11 * HREZZ12)
|| ((*hPrint)->rPaper.bottom -
(*hPrint)->rPaper.top > 11 * VREZZ)
|| ((*hPrint)->prStl.feed != feedCut &&
(*hPrint)->prStl.feed != feedFanfold)
|| ((*hPrint)->prJob.bJDocLoop != bDraftLoop))
return FALSE;
else return TRUE;
}
void free(ptr)
char *ptr;
{
asm{
move.l ptr,a0
DisposPtr
}
}
flipRect(rect)
Rect *rect;
{
asm{
move.l rect,a0
move.l (a0),d0
swap d0 ;; swap top, left
move.l d0,(a0)+
move.l (a0),d0
swap d0 ;; swap bottom, right
move.l d0,(a0)
}
}
#include "mkDefault.c"